package com.adkun.community.service;

import com.adkun.community.dao.AlphaDao;
import com.adkun.community.dao.DiscussPostMapper;
import com.adkun.community.dao.UserMapper;
import com.adkun.community.entity.DiscussPost;
import com.adkun.community.entity.User;
import com.adkun.community.util.CommunityUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.Date;

@Service
//@Scope("prototype")
// 如果声明为prototype，则每次getBean()时实例化一次容器。
// 如果声明为singleton，则程序启动时实例化容器。
@Slf4j
public class AlphaService {
    @Autowired
    private AlphaDao alphaDao;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private DiscussPostMapper discussPostMapper;

    // REQUIRED：支持当前事务（外部事务），如果不存在则创建新事务。必须有事务。
    // REQUIRES_NEW：创建一个新的事务，并暂停当前事务（外部事务）。永远创建一个新事务。
    // NESTED：如果当前存在事务（外部事务），则嵌套在该事务中执行（独立的提交和回滚），否则就和REQUIRED一样
    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
    public Object save1() {
        // 新增用户
        User user = new User();
        user.setUsername("alpha");
        user.setSalt(CommunityUtil.generateUUID().substring(0, 5));
        user.setPassword(CommunityUtil.md5("ssssssss" + user.getSalt()));
        user.setEmail("alpha@qq.com");
        user.setHeaderUrl("http://image.nowcoder.com/head/99t.png");
        user.setCreateTime(new Date());
        userMapper.insertUser(user);

        // 新增帖子
        DiscussPost discussPost = new DiscussPost();
        discussPost.setUserId(user.getId());
        discussPost.setTitle("Hello");
        discussPost.setContent("新人报道！" + user.getUsername());
        discussPost.setCreateTime(new Date());
        discussPostMapper.insertDiscussPost(discussPost);

        // 随便报个错看事务能不能回滚
        Integer.valueOf("abc");

        return "ok";
    }

    @Autowired
    private TransactionTemplate transactionTemplate;

    public Object save2() {
        transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
        transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

        // 会对这个方法进行事务管理。返回结果会被execute()返回
        return transactionTemplate.execute(transactionStatus -> {
            User user = new User();
            user.setUsername("alpha1");
            user.setSalt(CommunityUtil.generateUUID().substring(0, 5));
            user.setPassword(CommunityUtil.md5("ssssssss" + user.getSalt()));
            user.setEmail("alpha@qq.com");
            user.setHeaderUrl("http://image.nowcoder.com/head/999t.png");
            user.setCreateTime(new Date());
            userMapper.insertUser(user);

            // 新增帖子
            DiscussPost discussPost = new DiscussPost();
            discussPost.setUserId(user.getId());
            discussPost.setTitle("你好");
            discussPost.setContent("我是新人，新人报道！" + user.getUsername());
            discussPost.setCreateTime(new Date());
            discussPostMapper.insertDiscussPost(discussPost);

            // 随便报个错看事务能不能回滚
            Integer.valueOf("abc");

            return null;
        });
    }

    public AlphaService() {
        System.out.println("实例化AlphaService");
    }

    @PostConstruct
    public void init() {
        System.out.println("初始化AlphaService");
    }

    @PreDestroy
    public void destroy() {
        System.out.println("销毁AlphaService");
    }

    /**
     * @Async 让该方法在多线程环境下被异步调用
     */
    @Async
    public void execute1() {
        log.info("execute1");
    }

    /**
     * @Scheduled 定时任务
     */
//    @Scheduled(initialDelay = 10000, fixedRate = 1000)
    public void execute2() {
        log.info("execute2");
    }
}
